package com.xyzq.cgate.core.plugin.pre;

import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.xyzq.cgate.common.constant.Constants;
import com.xyzq.cgate.common.entity.Sign;
import com.xyzq.cgate.common.enums.OpenStateEnum;
import com.xyzq.cgate.common.enums.PluginDetailEnum;
import com.xyzq.cgate.common.rule.custom.entity.ComplexRule;
import com.xyzq.cgate.common.rule.custom.entity.MatchCondition;
import com.xyzq.cgate.common.utils.Md5Util;
import com.xyzq.cgate.core.cache.CacheManager;
import com.xyzq.cgate.core.plugin.AbstractPlugin;
import com.xyzq.cgate.core.plugin.IPluginChain;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Comparator;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description:
 * @author chenchen
 * @date 2019/6/19 13:56
 */
public class SignPlugin extends AbstractPlugin {

    private static final Logger LOGGER = LoggerFactory.getLogger(SignPlugin.class);

    private final CacheManager cacheManager;

    public SignPlugin(final CacheManager cacheManager) {
        super(cacheManager);
        this.cacheManager = cacheManager;
    }


    @Override
    protected Mono<Void> doExecute(ServerWebExchange exchange, IPluginChain chain, ComplexRule rule) {
        MatchCondition requestCondition = (MatchCondition) exchange.getAttributes()
                             .get(Constants.REQUESTDTO);
        String request_appKey = requestCondition.getAppKey();
        if(StringUtils.isNoneBlank(request_appKey) && StringUtils.equalsIgnoreCase(request_appKey, rule.getAppKey())) {
            //Optional.ofNullable(sign).ifPresent(s -> {
                if(OpenStateEnum.OPEN.getCode().equals(rule.getEnabled())) {
                    if(!verifySign(requestCondition, rule)) {
                        ServerHttpResponse response = exchange.getResponse();
                        response.setStatusCode(HttpStatus.UNAUTHORIZED);
                        return response.writeWith(Mono.just(exchange.getResponse()
                                .bufferFactory().wrap(HttpStatus.UNAUTHORIZED.getReasonPhrase().getBytes())));
                    }

                }
            //});
        }
        return chain.execute(exchange);
    }

    private boolean verifySign(MatchCondition requestCondition, ComplexRule rule) {
        String request_signCode = requestCondition.getSignCode();
        String md5Sign = Md5Util.getMD5(mapToString(requestCondition), rule.getAppSecret());
        if(StringUtils.equalsIgnoreCase(request_signCode, md5Sign)) {
            return true;
        }
        return false;
    }

    private String mapToString(MatchCondition requestCondition) {
        Map paramMap = Maps.newHashMapWithExpectedSize(4);
        buildParamMap(paramMap, requestCondition);
        return Stream.of(Constants.MODULE, Constants.METHOD, Constants.IP, Constants.RPC_TYPE)
                .sorted(Comparator.naturalOrder())
                .map(k -> Joiner.on("").join(k, paramMap.get(k).toString()))
                .collect(Collectors.joining())
                .trim();
    }

    private void buildParamMap(Map map, MatchCondition requestCondition) {
        map.put(Constants.MODULE, requestCondition.getModule());
        map.put(Constants.METHOD, requestCondition.getMethod());
        map.put(Constants.IP, requestCondition.getIp());
        map.put(Constants.RPC_TYPE, requestCondition.getRpcType());
    }

    @Override
    public String getPluginPhase() {
        return PluginDetailEnum.SIGN.getPhase();
    }

    @Override
    public int getCode() {
        return PluginDetailEnum.SIGN.getCode();
    }

    @Override
    public String getName() {
        return PluginDetailEnum.SIGN.getName();
    }
}
